package com.leyou.search.service;

import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.common.vo.PageResult;
import com.leyou.item.client.ItemClient;
import com.leyou.item.dto.BrandDTO;
import com.leyou.item.dto.CategoryDTO;
import com.leyou.item.dto.SpecParamDTO;
import com.leyou.search.dto.SearchRequest;
import com.leyou.search.pojo.Goods;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilterBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class SearchService {
    @Autowired
    private ElasticsearchTemplate esTemplate;
    @Autowired
    private ItemClient itemClient;

    /**
     * 根据搜索条件进行查询
     * @param searchRequest
     * @return
     */
    public PageResult<Goods> pageQuery(SearchRequest searchRequest) {
        String key = searchRequest.getKey();
        if (StringUtils.isBlank(key)){
            throw new LyException(ExceptionEnum.INVALID_FILE_TYPE);
        }
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

        queryBuilder.withQuery(buildBasicQuery(searchRequest));
        //springDate中的分页默认从0开始，所以减一
        queryBuilder.withPageable(PageRequest.of(searchRequest.getPage()-1,searchRequest.getSize()));
        //执行分页查询
        AggregatedPage<Goods> goods = esTemplate.queryForPage(queryBuilder.build(), Goods.class);

        //三个参数，总页数，总个数，信息
        return new PageResult<>(goods.getTotalElements(),goods.getTotalPages(),goods.getContent());

    }

    /**
     * 根据查询条件查询过滤条件（聚合）
     * @param searchRequest
     * @return
     */
    public Map<String, List<?>> filterQuery(SearchRequest searchRequest) {
        Map<String,List<?>> results =new LinkedHashMap<>();
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //聚合时候不展示查询结果，不能为零，size为1
        queryBuilder.withPageable(PageRequest.of(0,1));
        //查询展示一个值，字段不要显示
        queryBuilder.withSourceFilter(new FetchSourceFilterBuilder().build());
        QueryBuilder query = buildBasicQuery(searchRequest);
        queryBuilder.withQuery(query);
        //添加聚合条件
        String BRAND_AGGS ="brands";
        String CATEGORY_AGGS ="categories";
        queryBuilder.addAggregation(AggregationBuilders.terms(BRAND_AGGS).field("brandId"));
        queryBuilder.addAggregation(AggregationBuilders.terms(CATEGORY_AGGS).field("categoryId"));
        AggregatedPage<Goods> goodsAggregatedPage = this.esTemplate.queryForPage(queryBuilder.build(), Goods.class);
        //解析聚合
        Aggregations aggregations = goodsAggregatedPage.getAggregations();
        LongTerms brandTerms= aggregations.get(BRAND_AGGS);
        //获取品牌的聚合结果，取出品牌的Id
        List<Long> brandIds = brandTerms.getBuckets()
                .stream()
                .map(LongTerms.Bucket::getKeyAsNumber)
                .map(Number::longValue)
                .collect(Collectors.toList());
        LongTerms categoryTerms = aggregations.get(CATEGORY_AGGS);
        //获取分类的Id
        List<Long> categoryIds = categoryTerms.getBuckets().stream()
                .map(LongTerms.Bucket::getKeyAsNumber)
                .map(Number::longValue)
                .collect(Collectors.toList());
        //把集合转为对应的对象
        List<BrandDTO> brandDTOS = this.itemClient.queryBrandByBrandIds(brandIds);
        List<CategoryDTO> categoryDTOS = this.itemClient.queryByIds(categoryIds);
        results.put("分类",categoryDTOS);
        results.put("品牌",brandDTOS);
        if (null!=categoryIds||1==categoryIds.size()){
            //获取其他参数的方法，三个参数，分类的Id，
            getSpec(categoryIds.get(0),query,results);
        }
        return results;

    }

    private void getSpec(Long cid, QueryBuilder query, Map<String, List<?>> results) {
        //根据可搜索规格参数，名称进行聚合
        List<SpecParamDTO> specParamDTOS = this.itemClient.querySpecParamByGid(null, cid, true);
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //聚合时候不展示查询结果，不能为零，size为1
        queryBuilder.withPageable(PageRequest.of(0,1));
        //查询展示一个值，字段不要显示
        queryBuilder.withSourceFilter(new FetchSourceFilterBuilder().build());
        queryBuilder.withQuery(query);
        //添加聚合条件
        specParamDTOS.forEach(specParamDTO -> {
         String name =   specParamDTO.getName();
         queryBuilder.addAggregation(AggregationBuilders.terms(name).field("specs."+name+".keyword"));
        });
        //执行查询聚合
        AggregatedPage<Goods> goodsAggregatedPage = this.esTemplate.queryForPage(queryBuilder.build(), Goods.class);
        //解析聚合
        Aggregations aggregations = goodsAggregatedPage.getAggregations();
        specParamDTOS.forEach(specParamDTO -> {
          String name =  specParamDTO.getName();
          StringTerms stringTerms = aggregations.get(name);
            List<String> resultList = stringTerms.getBuckets()
                    .stream()
                    .map(StringTerms.Bucket::getKeyAsString)
                    .collect(Collectors.toList());
            //把聚合的获取的规格参数的列表存入到结果中
            results.put(name,resultList);
        });

    }

    private QueryBuilder buildBasicQuery(SearchRequest request) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.matchQuery("all", request.getKey()).operator(Operator.AND));
        Map<String, String> filter = request.getFilter();
        Set<Map.Entry<String, String>> entries = filter.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            String key = entry.getKey();
            String value = entry.getValue();
            if ("分类".equals(key)){
                queryBuilder.filter(QueryBuilders.termQuery("categoryId",value));
            }else if ("品牌".equals(key)){
                queryBuilder.filter(QueryBuilders.termQuery("brandId",value));
            }else {
                queryBuilder.filter(QueryBuilders.termQuery("spec."+key+".keyword",value));
            }

        }
        // 构建基本的match查询
        return queryBuilder;
    }
}
